import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Panda implements Drawable {
	Image pandimage;
	Physics phy;
	int nbSprites;
	int dirx;
	int diry;
	int oldDx;
	int oldDy;
	int x;
	int y;

	public enum Dir {
		U, D, R, L
	}

	Dir body;
	Dir face;

	static final Dir[][][][] transformations = {
			{
					{ {/* URU */Dir.L, Dir.U }, {/* URD */Dir.R, Dir.D },
							{/* URR */Dir.U, Dir.R }, {/* URL */Dir.U, Dir.L } },
					{ {/* ULU */Dir.R, Dir.U }, {/* ULD */Dir.L, Dir.D },
							{/* ULR */Dir.U, Dir.R }, {/* ULL */Dir.U, Dir.L } } },
			{
					{ { /* DRU */Dir.R, Dir.U }, {/* DRD */Dir.L, Dir.D },
							{/* DRR */Dir.D, Dir.R }, {/* DRL */Dir.D, Dir.L } },
					{ {/* DLU */Dir.L, Dir.U }, {/* DLD */Dir.R, Dir.D },
							{/* DLR */Dir.D, Dir.R }, {/* DLL */Dir.D, Dir.L } } },
			{
					{ {/* RUU */Dir.R, Dir.U }, {/* RUD */Dir.R, Dir.D },
							{/* RUR */Dir.D, Dir.R }, {/* RUL */Dir.U, Dir.L } },
					{ {/* RDU */Dir.R, Dir.U }, {/* RDD */Dir.R, Dir.D },
							{/* RDR */Dir.U, Dir.R }, {/* RDL */Dir.D, Dir.L } } },
			{
					{ {/* LUU */Dir.L, Dir.U }, {/* LUD */Dir.L, Dir.D },
							{/* LUR */Dir.U, Dir.R }, {/* LUL */Dir.D, Dir.L } },
					{ {/* LDU */Dir.L, Dir.U }, {/* LDD */Dir.L, Dir.D },
							{/* LDR */Dir.D, Dir.R }, {/* LDL */Dir.U, Dir.L } } } };

	public Panda() {
		this.x = 50;
		this.y = 50;
		this.oldDx = 1;
		this.oldDy = 0;
		this.body = Dir.U;
		this.face = Dir.R;
		this.nbSprites = 0;
		this.phy = new Physics();
		try {
			this.pandimage = ImageIO.read(new File("Sprite-Master.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void transformSprite(AffineTransform transform, Dir body, Dir face) {
		transform.translate(this.x, this.y);
		switch (body) {
		case U:
			if (face == Dir.L) {
				transform.scale(-1, 1);
			}
			break;
		case D:
			transform.rotate(Math.toRadians(180));
			if (face == Dir.R) {
				transform.scale(-1, 1);
			}
			break;
		case R:
			transform.rotate(Math.toRadians(90));
			if (face == Dir.U) {
				transform.scale(-1, 1);
			}
			break;
		case L:
			transform.rotate(Math.toRadians(-90));
			if (face == Dir.D) {
				transform.scale(-1, 1);
			}
		}
	}

	public void setDirx(int x) {
		this.dirx = x;
	}

	public void setDiry(int y) {
		this.diry = y;
	}

	public Dir computeDir(int dirx, int diry) {
		if (dirx == 1)
			return Dir.R;
		else if (diry == 1)
			return Dir.D;
		else if (diry == -1)
			return Dir.U;
		else if (dirx == -1)
			return Dir.L;
		return computeDir(oldDx, oldDy);
	}

	public int index2FromDir(Dir d) {
		switch (d) {
		case U:
			return 0;
		case D:
			return 1;
		case R:
			return 0;
		case L:
			return 1;
		default:
			return 0;
		}
	}

	public int index4FromDir(Dir d) {
		switch (d) {
		case U:
			return 0;
		case D:
			return 1;
		case R:
			return 2;
		case L:
			return 3;
		default:
			return 0;
		}
	}

	public void update() {
		if ((dirx != 0) || (diry != 0)) {
			++this.nbSprites;
			this.nbSprites %= 6;
			++this.nbSprites;
		} else
			this.nbSprites = 0;
		if (this.phy.checkPhysics(this.x + 10 * this.dirx, 
									this.y + 10* this.diry)) {
			this.x += 10 * this.dirx;
			this.y += 10 * this.diry;
		}

		if (this.dirx != 0 || this.diry != 0) {
			this.oldDx = this.dirx;
			this.oldDy = this.diry;
		}
		this.updateSpriteState();
	}

	public void updateSpriteState() {

		Dir dir = computeDir(this.dirx, this.diry);

		this.body = transformations[index4FromDir(body)][index2FromDir(face)][index4FromDir(dir)][0];
		this.face = transformations[index4FromDir(body)][index2FromDir(face)][index4FromDir(dir)][1];
	}

	@Override
	public void display(Graphics2D g, JPanel p) {
		AffineTransform saveXform = g.getTransform();
		AffineTransform transform = new AffineTransform(saveXform);
		this.transformSprite(transform, this.body, this.face);
		g.transform(transform);
		g.drawImage(this.pandimage, -50, -50, 50, 50, (this.nbSprites) * 100,
				0, (this.nbSprites + 1) * 100, 100, null);
		g.setTransform(saveXform);
	}
}
